package mobilefeel.touchscreen;

import java.util.ArrayList;
import java.util.List;

import mobilefeel.AndroidDevice;
import mobilefeel.dto.TouchEvent;

/**
 * Represents an Android device's touchscreen. TouchScreen allows the developer
 * to manage {@link ViewListener}'s, search them by ID or obtain the registered
 * views.
 */
public final class TouchScreen {

	private AndroidDevice android;
	private List<View> views;
	private List<ViewListener> listeners;
	
	private TouchScreen(AndroidDevice androidDevice){
		this.android = androidDevice;
		views = new ArrayList<View>();
		listeners = new ArrayList<ViewListener>();
	}
	
	/**
	 * Returns the TouchScreen instance linked to the {@link AndroidDevice}.
	 * 
	 * @param androidDevice the desired {@link AndroidDevice} (cannot be null)
	 * @return a TouchScreen instance representing the device's touchscreen
	 * @see AndroidDevice#getTouchScreen()
	 */
	public static TouchScreen getInstance(AndroidDevice androidDevice) {
		if (androidDevice == null)
			throw new IllegalArgumentException("androidDevice cannot be null.");
		
		if (androidDevice.getTouchScreen() == null)
			return new TouchScreen(androidDevice);
		return androidDevice.getTouchScreen();
	}
	
	private void addView(View view) {
		views.add(view);
	}
	
	/**
	 * Returns a list of the views registered by the Android device.
	 * 
	 * @return a list containing a {@link View} instance for each registered
	 * view
	 */
	public List<View> getViews() {
		return new ArrayList<View>(views);
	}
	
	/**
	 * Registers a callback to be invoked when an Android device registers a 
	 * view.
	 * 
	 * @param listener the {@link ViewListener} that will be notified of
	 * registered views (cannot be null)
	 * @see #removeViewListener(ViewListener)
	 */
	public void addViewListener(ViewListener listener) {
		if (listener == null)
			throw new IllegalArgumentException("listener cannot be null.");
		listeners.add(listener);
	}
	
	/**
	 * Unregisters a view listener.
	 * 
	 * @param listener the {@link ViewListener} that will not be notified of
	 * registered views anymore
	 * @see #addViewListener(ViewListener)
	 */
	public void removeViewListener(ViewListener listener) {
		listeners.remove(listener);
	}

	void registerView(int id, String name, int width, int height) {
		View view = null;
		for(View v : this.views)
			if(v.getId() == id){
				view = v;
			}
		if (view == null) {
			view = new View(this.android);
			this.addView(view);
		}
		view.setName(name);
		view.setId(id);
		view.setWidth(width);
		view.setHeight(height);
		notifyViewListeners(view);
	}
	
	private synchronized void notifyViewListeners(View view) {
		for (ViewListener listener : this.listeners)
			listener.onViewRegistered(android, view);
	}

	/**
	 * Finds a view by its hexadecimal ID.
	 * 
	 * @param id the hexadecimal view ID
	 * @return the corresponding {@link View} instance if found or null
	 * otherwise
	 */
	public View findViewById(int id) {
		for (View view : this.views)
			if (view.getId() == id)
				return view;
		return null;
	}

	void clickEvent(int id) {
		View view = findViewById(id);
		if (view != null) {
			view.notifyOnClickListeners();
		}
	}
	
	void longClickEvent(int id) {
		View view = findViewById(id);
		if (view != null) {
			view.notifyOnLongClickListeners();
		}
	}
	
	void touchEvent(TouchEvent event) {
		View view = findViewById(event.getId());
		if (view != null) {
			view.notifyOnTouchListeners(event);
		}
	}

}